package com.yfp.machine.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.json.JSONObject;
import com.github.pagehelper.PageInfo;
import com.yfp.common.core.constant.CacheConstants;
import com.yfp.common.core.constant.DbConstants;
import com.yfp.common.core.domain.R;
import com.yfp.common.core.utils.bean.BeanUtils;
import com.yfp.machine.domain.Machine;
import com.yfp.machine.domain.PositionType;
import com.yfp.machine.domain.dto.*;
import com.yfp.machine.domain.vo.CoordinateLimitSummaryVo;
import com.yfp.machine.domain.vo.CoordinateSearchLimitNameVo;
import com.yfp.machine.domain.vo.FilterDeviceInfoVo;
import com.yfp.machine.domain.vo.SearchBasicInfoVo;
import com.yfp.machine.mapper.AppletMachineMapper;
import com.yfp.machine.service.AppletMachineService;
import com.yfp.machine.service.MachineService;
import com.yfp.machine.domain.dto.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

import static com.github.pagehelper.page.PageMethod.startPage;

@Slf4j
@Service("appletMachineService")
public class AppletMachineServiceImpl implements AppletMachineService {

    @Resource
    MachineService machineService;

    @Resource
    AppletMachineMapper appletMachineMapper;

    @Resource
    RedisTemplate redisTemplate;


    @Override
    public R deviceLimitBasicInfo(FilterDeviceInfoVo filterDeviceInfoVo) {
        Integer pageIndex = filterDeviceInfoVo.getPageIndex();
        Integer pageSize = filterDeviceInfoVo.getPageSize();
        String machineType = filterDeviceInfoVo.getMachineType();
        String machineLabel = filterDeviceInfoVo.getMachineLabel();
        String positionTypeId = filterDeviceInfoVo.getPositionTypeId();
        startPage(pageIndex, pageSize);
        List<FilterDeviceInfo> machineList = appletMachineMapper.deviceLimitBasicInfo(Integer.valueOf(machineType), machineLabel, positionTypeId);
        if (CollUtil.isEmpty(machineList)) return R.fail("未查询到相关数据");
        PageInfo<FilterDeviceInfo> pageInfo = new PageInfo<>(machineList);
        return R.ok(pageInfo);
    }

    @Override
    public R positionTypeSearchBasicInfo(SearchBasicInfoVo searchBasicInfoVo) {
        Integer pageIndex = searchBasicInfoVo.getPageIndex();
        Integer pageSize = searchBasicInfoVo.getPageSize();
        String word = searchBasicInfoVo.getWord();
        startPage(pageIndex, pageSize);
        List<SearchBasicInfo> searchBasicInfoeList = appletMachineMapper.positionTypeSearchBasicInfo(word);
        if (CollUtil.isEmpty(searchBasicInfoeList)) return R.fail("未查询到相关数据");
        PageInfo<SearchBasicInfo> pageInfo = new PageInfo<>(searchBasicInfoeList);
        return R.ok(pageInfo);
    }

    @Override
    public R deviceCoordinateLimitSummary(CoordinateLimitSummaryVo coordinateLimitSummaryVo) {
        Integer pageIndex = coordinateLimitSummaryVo.getPageIndex();
        Integer pageSize = coordinateLimitSummaryVo.getPageSize();
        String latitude = coordinateLimitSummaryVo.getLatitude();
        String longitude = coordinateLimitSummaryVo.getLongitude();
        Double maxRange = coordinateLimitSummaryVo.getMaxRange();



        List<CoordinateSearchLimitName> coordinateLimitSummaryList = getCoordinateList(longitude, latitude, maxRange);

        if (CollUtil.isEmpty(coordinateLimitSummaryList)) return R.fail("未查询到相关数据");

        //排序分页
        List<CoordinateSearchLimitName> list = coordinateLimitSummaryList.stream()
                .sorted(Comparator.comparing(CoordinateSearchLimitName::getDistanceCenterPoint))
                .skip((long) (pageIndex - 1) * pageSize)
                .limit(pageSize)
                .toList();

        ArrayList<CoordinateLimitSummary> coordinateLimitSummaries = new ArrayList<>();
        list.forEach(l -> {
            CoordinateLimitSummary coordinateLimitSummary = new CoordinateLimitSummary();
            BeanUtils.copyBeanProp(coordinateLimitSummary, l);
            coordinateLimitSummaries.add(coordinateLimitSummary);
        });
        log.info("coordinateLimitSummaries:{}", coordinateLimitSummaries);
        CoordinateLimitSummaryDto coordinateLimitSummaryDto = new CoordinateLimitSummaryDto();
        coordinateLimitSummaryDto.setMachineList(coordinateLimitSummaries);
        coordinateLimitSummaryDto.setCount((long) coordinateLimitSummaryList.size());
        return R.ok(coordinateLimitSummaryDto);
    }

    @NotNull
    private List<CoordinateSearchLimitName> getCoordinateList(String longitude, String latitude, Double maxRange) {
        //检查缓存
        whetherCacheIsExistence();

        Point point = new Point(Double.parseDouble(longitude), Double.parseDouble(latitude));

        Metric metric = RedisGeoCommands.DistanceUnit.KILOMETERS;
        Distance distance = new Distance(maxRange, metric);
        Circle circle = new Circle(point, distance);

        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands
                .GeoRadiusCommandArgs
                .newGeoRadiusArgs()
                .includeDistance()
                .includeCoordinates()
                .sortAscending();

        GeoResults<RedisGeoCommands.GeoLocation<String>> radius = redisTemplate.
                opsForGeo().radius(CacheConstants.GEO_MACHINE_KEY, circle, args);

        List<CoordinateSearchLimitName> coordinateList = new ArrayList<>();

        if (radius != null) {
            for (GeoResult<RedisGeoCommands.GeoLocation<String>> geoLocationGeoResult : radius) {
                CoordinateSearchLimitName coordinate = new CoordinateSearchLimitName();
                RedisGeoCommands.GeoLocation<String> content = geoLocationGeoResult.getContent();
                //member 名称  如  machineId
                String machineId = content.getName();
                // 距离中心点的距离
                double dis = geoLocationGeoResult.getDistance().getValue();
                coordinate.setDistanceCenterPoint(dis);
                coordinate.setMachineId(machineId);

                MachineDto machineDto = this.machineService.queryMachineInfoById(machineId);
                if (Objects.isNull(machineDto) || DbConstants.DISABLED_ABNORMAL.equals(machineDto.getEnable())){
                    continue;
                }

                coordinate.setMachineName(machineDto.getMachineName());
                coordinate.setPositionAddr(machineDto.getPositionAddr());
                coordinate.setLatitude(machineDto.getLatitude());
                coordinate.setLongitude(machineDto.getLongitude());
                coordinate.setSaleBeginTime(machineDto.getSaleBeginTime());
                coordinate.setSaleEndTime(machineDto.getSaleEndTime());
                coordinateList.add(coordinate);
            }
        }
        log.info("查询设备坐标点列表：{}", coordinateList);
        if (CollUtil.isEmpty(coordinateList)) return Collections.emptyList();
        return coordinateList;
    }

    @Override
    public R deviceCoordinateSearchLimitName(CoordinateSearchLimitNameVo coordinateLimitSummaryVo) {

        Integer pageIndex = coordinateLimitSummaryVo.getPageIndex();
        Integer pageSize = coordinateLimitSummaryVo.getPageSize();
        String word = coordinateLimitSummaryVo.getWord();
        String latitude = coordinateLimitSummaryVo.getLatitude();
        String longitude = coordinateLimitSummaryVo.getLongitude();
        Double maxRange = coordinateLimitSummaryVo.getMaxRange();

        List<CoordinateSearchLimitName> coordinateLimitSummaryList = getCoordinateList(longitude, latitude, maxRange);

        if (CollUtil.isEmpty(coordinateLimitSummaryList)) return R.fail("未查询到相关数据");

        //关键字过滤
        List<CoordinateSearchLimitName> eligibleData = coordinateLimitSummaryList.stream()
                .filter(c -> c.getMachineName().contains(word)).toList();

        if (CollUtil.isEmpty(eligibleData)) return R.fail("未查询到相关数据");

        //排序分页
        List<CoordinateSearchLimitName> list = eligibleData.stream()
                .sorted(Comparator.comparing(CoordinateSearchLimitName::getDistanceCenterPoint))
                .skip((long) (pageIndex - 1) * pageSize)
                .limit(pageSize)
                .toList();

        if (CollUtil.isEmpty(list)) return R.fail("未查询到相关数据");
        log.info("coordinateLimitSummaries:{}", list);
        CoordinateSearchLimitNameDto coordinateLimitSummaryDto = new CoordinateSearchLimitNameDto();
        coordinateLimitSummaryDto.setMachineList(list);
        coordinateLimitSummaryDto.setCount((long) eligibleData.size());

        return R.ok(coordinateLimitSummaryDto);
    }

    /**
     * 根据设备id获取营业时间
     *
     * @param machineId 机器id
     * @return {@link R}
     */
    @Override
    public R getSaleTimeByMachineId(String machineId) {
        PositionType positionType = appletMachineMapper.getSaleTimeByMachineId(machineId);
        if (Objects.isNull(positionType) || CharSequenceUtil.isEmpty(positionType.getSaleBeginTime())
                || CharSequenceUtil.isEmpty(positionType.getSaleEndTime())) return R.fail("未查询到相关数据");
        JSONObject result = new JSONObject();
        result.set("saleBeginTime", positionType.getSaleBeginTime());
        result.set("saleEndTime", positionType.getSaleEndTime());
        return R.ok(result);
    }

    /**
     * 按id获取机器
     *
     * @param machineId 机器id
     * @return {@link R}
     */
    @Override
    public Machine getMachineById(String machineId) {
        return machineService.getMachineById(machineId);
    }


    private void whetherCacheIsExistence() {
        Boolean hasKey = redisTemplate.hasKey(CacheConstants.GEO_MACHINE_KEY);
        if (Boolean.FALSE.equals(hasKey)) {
            machineService.resetConfigCache();
        }
    }

    public static void main(String[] args) {
        System.out.println(Double.parseDouble("120.19136534789172"));
    }
}
